home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic Source Code
/
Visual Basic Source Code.iso
/
vbsource
/
metkit
/
setup.exe
/
EXAMPLES
/
KBIND
/
KBOUNDW.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-08
|
8KB
|
234 lines
// Copyright (C) 1996, 1997 Meta Four Software. All rights reserved.
//
// See the comments in "kbound.h" for details on how to use this code.
//
//! rev="$Id: kboundw.cpp,v 1.2 1997/05/27 00:06:45 jcw Rel $"
#include "kbound.h"
/////////////////////////////////////////////////////////////////////////////
//
// THE LZRW1 ALGORITHM
// ===================
// Author : Ross N. Williams.
// Date : 31-Mar-1991.
//
// 1. I typed the following code in from my paper "An Extremely Fast Data
// Compression Algorithm", Data Compression Conference, Utah, 7-11 April,
// 1991. The fact that this code works indicates that the code in the
// paper is OK.
//
// 2. This file has been copied into a test harness and works.
//
// 3. Some users running old C compilers may wish to insert blanks around
// the "=" symbols of assignments so as to avoid expressions such as
// "a=*b;" being interpreted as "a=a*b;"
//
// 4. This code is public domain.
//
// 5. Warning: This code is non-deterministic insofar as it may yield
// different compressed representations of the same file on different
// runs. (However, it will always decompress correctly to the original).
//
// 6. If you use this code in anger (e.g. in a product) drop me a note at
// ross@spam.ua.oz.au and I will put you on a mailing list which will be
// invoked if anyone finds a bug in this code.
//
// 7. The internet newsgroup comp.compression might also carry
// information on this algorithm from time to time.
//
/////////////////////////////////////////////////////////////////////////////
#define FLAG_BYTES 2 /* Number of bytes used by copy flag. */
#define FLAG_COMPRESS 0 /* Signals that compression occurred. */
#define FLAG_COPY 1 /* Signals that a copyover occurred. */
static void fast_copy(BYTE *p_src,BYTE *p_dst,int len) /* Fast copy routine. */
{while (len--) *p_dst++=*p_src++;}
void lzrw1_compress(BYTE *p_src_first,DWORD src_len,
BYTE *p_dst_first,DWORD *p_dst_len)
/* Input : Specify input block using p_src_first and src_len. */
/* Input : Point p_dst_first to the start of the output zone (OZ). */
/* Input : Point p_dst_len to a DWORD to receive the output length. */
/* Input : Input block and output zone must not overlap. */
/* Output : Length of output block written to *p_dst_len. */
/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
/* Output : May write in OZ=Mem[p_dst_first..p_dst_first+src_len+256-1].*/
/* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */
#define PS *p++!=*s++ /* Body of inner unrolled matching loop. */
#define ITEMMAX 16 /* Maximum number of bytes in an expanded item. */
{BYTE *p_src=p_src_first,*p_dst=p_dst_first;
BYTE *p_src_post=p_src_first+src_len,*p_dst_post=p_dst_first+src_len;
BYTE *p_src_max1=p_src_post-ITEMMAX,*p_src_max16=p_src_post-16*ITEMMAX;
BYTE *hash[4096],*p_control; WORD control=0,control_bits=0;
*p_dst=FLAG_COMPRESS; p_dst+=FLAG_BYTES; p_control=p_dst; p_dst+=2;
while (1)
{BYTE *p,*s; WORD unroll=16,len,index; DWORD offset;
if (p_dst>p_dst_post) goto overrun;
if (p_src>p_src_max16)
{unroll=1;
if (p_src>p_src_max1)
{if (p_src==p_src_post) break; goto literal;}}
begin_unrolled_loop:
index=((40543*((((p_src[0]<<4)^p_src[1])<<4)^p_src[2]))>>4) & 0xFFF;
p=hash[index]; hash[index]=s=p_src; offset=s-p;
if (offset>4095 || p<p_src_first || offset==0 || PS || PS || PS)
{literal: *p_dst++=*p_src++; control>>=1; control_bits++;}
else
{PS || PS || PS || PS || PS || PS || PS ||
PS || PS || PS || PS || PS || PS || s++; len=s-p_src-1;
*p_dst++=(BYTE) (((offset&0xF00)>>4)+(len-1));
*p_dst++=(BYTE) (offset&0xFF);
p_src+=len; control=(control>>1)|0x8000; control_bits++;}
/* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop;
if (control_bits==16)
{*p_control=control&0xFF; *(p_control+1)=control>>8;
p_control=p_dst; p_dst+=2; control=control_bits=0;}
}
control>>=16-control_bits;
*p_control++=control&0xFF; *p_control++=control>>8;
if (p_control==p_dst) p_dst-=2;
*p_dst_len=p_dst-p_dst_first;
return;
overrun: fast_copy(p_src_first,p_dst_first+FLAG_BYTES,(int)src_len);
*p_dst_first=FLAG_COPY; *p_dst_len=src_len+FLAG_BYTES;
}
/////////////////////////////////////////////////////////////////////////////
class c4_BoundWriter : public CFile
{
BYTE *_begin, *_curr, *_end;
int _base;
CString _prefix;
CString _resIncText;
bool _asText;
public:
c4_BoundWriter (const char* prefix_, bool asText_, int base_)
: _prefix (prefix_), _asText (asText_), _base (base_)
{
_begin = _curr = new BYTE [c4_BoundStorage::kBlockSize];
_end = _begin + c4_BoundStorage::kBlockSize;
}
virtual ~c4_BoundWriter ()
{
FlushNextBlock();
delete [] _begin;
CFile out (_prefix + ".rc", CFile::modeWrite | CFile::modeCreate);
out.Write((const char*) _resIncText, _resIncText.GetLength());
}
virtual UINT Read(void* lpBuf, UINT nCount)
{
ASSERT(0);
return 0;
}
virtual void Write(const void* lpBuf, UINT nCount)
{
UINT n = nCount;
while (n > 0)
{
if (_curr >= _end)
FlushNextBlock();
int k = n;
if (k > _end - _curr)
k = _end - _curr;
memcpy(_curr, lpBuf, k);
_curr += k;
lpBuf = (const char*) lpBuf + k;
n -= k;
}
}
void FlushNextBlock()
{
if (_curr > _begin)
{
DWORD k = _curr - _begin;
ASSERT(k <= c4_BoundStorage::kBlockSize);
_curr = _begin;
c4_Bytes temp;
BYTE* tempBuf = temp.SetBuffer((int) k + 256 + FLAG_BYTES);
lzrw1_compress(_begin, k, tempBuf, &k);
ASSERT((int) k <= temp.Size() - 4);
ASSERT((int) k <= c4_BoundStorage::kBlockSize + FLAG_BYTES);
ASSERT(*tempBuf <= 1);
// save the exact stored length and the copy bit
*(WORD*) tempBuf = ((WORD) k << 1) + *tempBuf;
ASSERT(c4_BoundStorage::_Encoder);
c4_BoundStorage::_Encoder(true, _base - 1,
(char*) tempBuf + 2, k - 2);
char num [20];
wsprintf(num, "%03d", _base);
CString s = num;
if (_asText)
{
CFile out (_prefix + s + ".rc",
CFile::modeWrite | CFile::modeCreate);
CString line = s + " RCDATA\r\nBEGIN";
memset(tempBuf + k, 0, 4); // make sure trailing bytes are zero
for (WORD i = 0; i < k; i += sizeof (DWORD))
{
if (i % 32 == 0)
{
out.Write(line, line.GetLength());
line = "\r\n ";
}
wsprintf(num, "0x%08lxL,", *(const DWORD*) (tempBuf + i));
line += num;
}
line += "\r\nEND\r\n";
out.Write(line, line.GetLength());
_resIncText += "#include \"" + _prefix + s + ".rc\"\r\n";
}
else
{
CFile out (_prefix + s + ".res",
CFile::modeWrite | CFile::modeCreate);
out.Write(tempBuf, k);
_resIncText += s + " RCDATA \"" + _prefix + s + ".res\"\r\n";
}
}
++_base;
}
};
/////////////////////////////////////////////////////////////////////////////
int c4_BoundStorage::DumpAsRes(c4_Storage& orig_, const char* prefix_,
bool asText_, int base_)
{
c4_BoundWriter writer (prefix_, asText_, base_);
orig_.SaveToStream(&writer);
return 0;
}
/////////////////////////////////////////////////////////////////////////////